
import 'dart:typed_data';

class DataBuffer {
  late ByteData byteData;
  late int offsetInBytes = 0;
  DataBuffer(Uint8List data, [int offset = 0]) {
    if (offset <= 0) {
      offsetInBytes = data.offsetInBytes;
    }else{
      offsetInBytes=offset;
    }
    byteData = data.buffer.asByteData();
  }
  factory DataBuffer.capacity(int size) {
    return DataBuffer(Uint8List(size));
  }

  int readInt8() {
    int answer = byteData.getInt8(offsetInBytes);
    offsetInBytes += 1;
    return answer;
  }

  int readInt16BE() {
    int answer = byteData.getInt16(offsetInBytes, Endian.big);
    offsetInBytes += 2;
    return answer;
  }

  int readInt16LE() {
    int answer = byteData.getInt16(offsetInBytes, Endian.little);
    offsetInBytes += 2;
    return answer;
  }

  int readInt32BE() {
    int answer = byteData.getInt32(offsetInBytes, Endian.big);
    offsetInBytes += 4;
    return answer;
  }

  int readInt32LE() {
    int answer = byteData.getInt32(offsetInBytes, Endian.little);
    offsetInBytes += 4;
    return answer;
  }

  int readInt64BE() {
    int answer = byteData.getInt64(offsetInBytes, Endian.big);
    offsetInBytes += 8;
    return answer;
  }

  int readInt64LE() {
    int answer = byteData.getInt64(offsetInBytes, Endian.little);
    offsetInBytes += 8;
    return answer;
  }

  int readUInt8() {
    int answer = byteData.getUint8(offsetInBytes);
    offsetInBytes += 1;
    return answer;
  }

  int readUInt16BE() {
    int answer = byteData.getUint16(offsetInBytes, Endian.big);
    offsetInBytes += 2;
    return answer;
  }

  int readUInt16LE() {
    int answer = byteData.getUint16(offsetInBytes, Endian.little);
    offsetInBytes += 2;
    return answer;
  }

  int readUInt32BE() {
    int answer = byteData.getUint32(offsetInBytes, Endian.big);
    offsetInBytes += 4;
    return answer;
  }

  int readUInt32LE() {
    int answer = byteData.getUint32(offsetInBytes, Endian.little);
    offsetInBytes += 4;
    return answer;
  }

  int readUInt64BE() {
    int answer = byteData.getUint64(offsetInBytes, Endian.big);
    offsetInBytes += 8;
    return answer;
  }

  int readUInt64LE() {
    int answer = byteData.getUint64(offsetInBytes, Endian.little);
    offsetInBytes += 8;
    return answer;
  }

  double readFloat32BE() {
    double answer = byteData.getFloat32(offsetInBytes, Endian.big);
    offsetInBytes += 4;
    return answer;
  }

  double readFloat32LE() {
    double answer = byteData.getFloat32(offsetInBytes, Endian.little);
    offsetInBytes += 4;
    return answer;
  }

  double readFloat64BE() {
    double answer = byteData.getFloat64(offsetInBytes, Endian.big);
    offsetInBytes += 8;
    return answer;
  }

  double readFloat64LE() {
    double answer = byteData.getFloat64(offsetInBytes, Endian.little);
    offsetInBytes += 8;
    return answer;
  }

  String readStringBE() {
    int length = readUInt16BE();
    List<int> tmp = [];
    for (int i = 0; i < length; i++) {
      tmp.add(readInt8());
    }
    return String.fromCharCodes(tmp);
  }

  String readStringLE() {
    int length = readUInt16LE();
    List<int> tmp = [];
    for (int i = 0; i < length; i++) {
      tmp.add(readInt8());
    }
    return String.fromCharCodes(tmp);
  }

  void writeInt8(int value) {
    byteData.setInt8(offsetInBytes, value);
    offsetInBytes += 1;
  }

  void writeInt16BE(int value) {
    byteData.setInt16(offsetInBytes, value, Endian.big);
    offsetInBytes += 2;
  }

  void writeInt16LE(int value) {
    byteData.setInt16(offsetInBytes, value, Endian.little);
    offsetInBytes += 2;
  }

  void writeInt32BE(int value) {
    byteData.setInt32(offsetInBytes, value, Endian.big);
    offsetInBytes += 4;
  }

  void writeInt32LE(int value) {
    byteData.setInt32(offsetInBytes, value, Endian.little);
    offsetInBytes += 4;
  }

  void writeInt64BE(int value) {
    byteData.setInt64(offsetInBytes, value, Endian.big);
    offsetInBytes += 8;
  }

  void writeInt64LE(int value) {
    byteData.setInt64(offsetInBytes, value, Endian.little);
    offsetInBytes += 8;
  }

  void writeUInt8(int value) {
    byteData.setUint8(offsetInBytes, value);
    offsetInBytes += 1;
  }

  void writeUInt16BE(int value) {
    byteData.setUint16(offsetInBytes, value, Endian.big);
    offsetInBytes += 2;
  }

  void writeUInt16LE(int value) {
    byteData.setUint16(offsetInBytes, value, Endian.little);
    offsetInBytes += 2;
  }

  void writeUInt32BE(int value) {
    byteData.setInt32(offsetInBytes, value, Endian.big);
    offsetInBytes += 4;
  }

  void writeUInt32LE(int value) {
    byteData.setInt32(offsetInBytes, value, Endian.little);
    offsetInBytes += 4;
  }

  void writeUInt64BE(int value) {
    byteData.setInt64(offsetInBytes, value, Endian.big);
    offsetInBytes += 8;
  }

  void writeUInt64LE(int value) {
    byteData.setInt64(offsetInBytes, value, Endian.little);
    offsetInBytes += 8;
  }

  void writeFloat32BE(double value) {
    byteData.setFloat32(offsetInBytes, value, Endian.big);
    offsetInBytes += 4;
  }

  void writeFloat32LE(double value) {
    byteData.setFloat32(offsetInBytes, value, Endian.little);
    offsetInBytes += 4;
  }

  void writeFloat64BE(double value) {
    byteData.setFloat64(offsetInBytes, value, Endian.big);
    offsetInBytes += 8;
  }

  void writeFloat64LE(double value) {
    byteData.setFloat64(offsetInBytes, value, Endian.little);
    offsetInBytes += 8;
  }

  void writeStringBE(String value) {
    if (value.isEmpty) {
      return;
    }
    List<int> tmp = value.codeUnits;
    writeUInt16BE(tmp.length);
    for (var item in tmp) {
      writeInt8(item);
    }
  }

  void writeStringLE(String value) {
    if (value.isEmpty) {
      return;
    }
    List<int> tmp = value.codeUnits;
    writeUInt16LE(tmp.length);
    for (var item in tmp) {
      writeInt8(item);
    }
  }

  Uint8List toList() {
    return byteData.buffer.asUint8List(0, offsetInBytes);
  }
}
